/*
 * Copyright 2006-2007 S W McIlroy
 * Licensed  under the  Apache License,  Version 2.0  (the "License");
 * you may not use  this file  except in  compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed  under the  License is distributed on an "AS IS" BASIS,
 * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
 * implied.
 *
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.mockfu.junit;


import static org.mockfu.Exceptions.*;

import java.lang.reflect.Method;
import java.util.List;

import org.junit.runner.Description;
import org.junit.runner.RunWith;
import org.junit.runner.Runner;
import org.junit.runner.notification.RunNotifier;


/**
 * Automatic mock verifier for JUnit 4.x. Pass this class as an argument to the {@link RunWith}
 * annotation on a test class to enable for all tests in that class. This runner will also
 * automatically eject any injections that have not yet been ejected.
 */
public class Verifier extends Runner
{
    protected Runner delegate;


    public Verifier(Class<?> klass)
    {
        this(klass, false);
    }

    public Verifier(Class<?> klass, boolean parallelize)
    {
        try
        {
            try
            {
                Class<?> delegateClass = Class.forName("org.mockfu.junit.FourDotFourVerifier");
                delegate = (Runner)delegateClass.getConstructor(Class.class, boolean.class).newInstance(klass, parallelize);
            }
            catch (NoClassDefFoundError ex)
            {
                Class<?> delegateClass = Class.forName("org.mockfu.junit.FourDotOhVerifier");
                delegate = (Runner)delegateClass.getConstructor(Class.class, boolean.class).newInstance(klass, parallelize);
            }
        }
        catch (Exception ex)
        {
            throw undeclared(ex);
        }
    }


    /**
     * Called by ParallelSuite to get the test method annotations.
     */
    @SuppressWarnings("unchecked")
    List<Method> getTestMethods()
    {
        try
        {
            /* protected method on JUnitClassRunner */
            Method method = delegate.getClass().getSuperclass().getDeclaredMethod("getTestMethods");
            method.setAccessible(true);
            return (List<Method>)method.invoke(delegate);
        }
        catch (Exception ex)
        {
            throw undeclared(ex);
        }
    }

    @Override
    public Description getDescription()
    {
        return delegate.getDescription();
    }

    @Override
    public void run(RunNotifier notifier)
    {
        delegate.run(notifier);
    }

    @Override
    public int testCount()
    {
        return delegate.testCount();
    }

    @Override
    public boolean equals(Object obj)
    {
        return delegate.equals(obj);
    }

    @Override
    public int hashCode()
    {
        return delegate.hashCode();
    }

    @Override
    public String toString()
    {
        return delegate.toString();
    }

}
